/*================================================================
*   File Name：server.c
*   Mail: a1277992967@163.com 
*   blog: http://www.ycst.club/suggest/ 
*   Author：ycst
*   Created Time：2022年08月08日 星期一 18时40分21秒
*   Describe：服务器端
*
================================================================*/

#include "../include/server.h"

int main(int argc, char* argv[]){

/*================================================================
*   Describe：初始化部分
================================================================*/
	int op = 1;
	int parity = 0;
	char recv_buf[BUF_SIZE] = {0};
	char send_buf[BUF_SIZE] = {0};
	char *share_mem = NULL;
	Datapack *data = NULL;		//仅供宏函数使用，写下就行，可以不管
	Datapack data1;
	struct timeval timeout;
	
	int heart_bit = 0;
	char bb[100] = {0};

	int s_len = sizeof(sock_server);
	int c_len = sizeof(sock_client);
	int res = -1;
	
	sock_server.sin_family = AF_INET;
	sock_server.sin_port = htons(PORT);
	sock_server.sin_addr.s_addr = INADDR_ANY;

	int server_id = socket(AF_INET, SOCK_DGRAM, 0);
	setsockopt(server_id, SOL_SOCKET, SO_REUSEADDR, (void *)&op, sizeof(op));
	bind(server_id, (struct sockaddr *)&sock_server, sizeof(sock_server));

	timeout.tv_sec = 10;
	timeout.tv_usec = 0;
	setsockopt(server_id, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
	
	int memid = shmget(0x0010, 1024, IPC_CREAT | 0666);
	share_mem = shmat(memid, NULL, 0);
	*share_mem = heart_bit;
#if 0
/*================================================================
*   Describe：心跳检测，到期子进程如果没有发送消息，关闭客户端
================================================================*/

	int childid = fork();
	if(childid == 0){	
		printf("我子进程活了！\r\n");
		int temp = heart_bit;
		while(1){
			sleep(HEART_TIME);
			if(temp == *share_mem){
				printf("客户端已死，准备关闭服务器\r\n");
				kill(getppid(), SIGKILL);
				exit(0);
			}
		}
	}
	printf("我父进程活了！\r\n");
#endif

#if 1
/*================================================================
*   Describe：心跳检测，到期子进程如果没有发送消息，关闭客户端
================================================================*/

	int childid = fork();

	if(childid == 0){	
	    char exc_rec[100] = {0};    //data
	    int seq = 0;            	//seq
	    int ack = 0;            	//ack
	    int check = 0;          	//check
	    timeout.tv_sec = HEART_TIME;
	    timeout.tv_usec = 0;
	    setsockopt(server_id, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
	    printf("---------------我子进程活了！---------------\r\n");
	    while(1){
	        sleep(HEART_TIME);
		    bzero(recv_buf, sizeof(recv_buf));
		    bzero(exc_rec, sizeof(exc_rec));
		
		    recv_from_client(recv_buf);
		    
		    seq = get_seq(recv_buf);
		    ack = get_ack(recv_buf);
		    check = get_check(recv_buf);
		    get_data(recv_buf, exc_rec);
		    if(seq == 0 && ack == 0 && (check & BIT) == BIT && strcmp(exc_rec, "Heart bit") == 0){
		        printf("--------------客户端保持连接中---------------\r\n");
		        continue;
		    }
		    else{
		        printf("---------------客户端已关闭，关闭服务器---------------\r\n");
		        kill(getppid(), SIGKILL);
				exit(0);
		    }
	    }
		
	}
#endif
/*================================================================
*   Describe：正式开始主业务逻辑
================================================================*/
	
	Three_Handshakes(server_id);
	
	printf("---------------------------------------------------------\r\n");
#if 1
	bzero(recv_buf, sizeof(recv_buf));
	recv_from_client(recv_buf);
	server_error_req(recv_buf);
	heart_bit++;
	bzero(bb, sizeof(bb));
	get_data(recv_buf, bb);
	printf("客户端发来 ： %s \r\n", bb);
#endif
#if 1
	bzero(recv_buf, sizeof(recv_buf));
	data_init(data1, 0, 0, 0, "I Hear You\r\n");
	parity = Parity_Create(data1);
	if(parity == 1)	data1.check |= BIP;	
	printf("BIP = %d\r\n", data1.check);
	
	send_to_client(data1);
	server_error_resend(recv_buf, data1);
	heart_bit++;
#endif

	printf("---------------------------------------------------------\r\n");
	Four_Waves(server_id);
	kill(childid, SIGKILL);
	
	///send_to_client(data1);
	return 0;
}

/*================================================================
*   Describe : 三次握手
------------------------------------------------------------------
*	parameter	:
*	@server_id	:	服务器监听描述符	
================================================================*/

int Three_Handshakes(int server_id){
	
	char recv_buf[BUF_SIZE] = {0};	
	char send_buf[BUF_SIZE] = {0};
	Datapack data1;
	int parity = 0;
	int seq1 = 0, ack1 = 0, check1 = 0;
	int seq2 = 0, ack2 = 0, check2 = 0;
	int seq3 = 0, ack3 = 0, check3 = 0;
	int s_len = sizeof(sock_server);
	int c_len = sizeof(sock_client);
	char buf[100] = "";		//Verify message
	
/*================================================================
*   Describe：
*		第一次服务器接受握手	SYN = 1; seq = x;
================================================================*/
	printf("服务器：开始三次握手!\r\n");
	recv_from_client(recv_buf);
	server_error_req(recv_buf);
	printf("服务器：接收到数据!\r\n");
	seq1 = get_seq(recv_buf);
	ack1 = get_ack(recv_buf);
	check1 = get_check(recv_buf);
	bzero(buf, sizeof(buf));
	get_data(recv_buf, buf);
	
	if(seq1 != 0 && (check1 & SYN) > 0 && strcmp(buf, "VMS1") == 0){
		printf("服务器：第一次握手成功!\r\n");
	}
	else{
		printf("服务器：第一次握手失败!\r\n");
		printf("seq1 : %d\r\n", seq1);
		printf("ack1 : %d\r\n", ack1);
		printf("check1 : %d\r\n", check1);
		printf("my_data1 : %s\r\n", buf);
		return -1;
	}
	printf("seq1 : %d\r\n", seq1);
	printf("ack1 : %d\r\n", ack1);
	printf("check1 : %d\r\n", check1);
	printf("my_data1 : %s\r\n", buf);
	
/*================================================================
*   Describe：
*		第二次次服务器发起握手	SYN = 1; ACK = 1; seq = y; ack = x + 1
================================================================*/
	seq2 = rand() % 100 + 1;
	ack2 = seq1 + 1;
	check2 = SYN | ACK;
	bzero(buf, sizeof(buf));
	strcpy(buf, "VMS2");
	data_init(data1, seq2, ack2, check2, buf);
	BP(data1);
	send_to_client(data1);
	server_error_resend(recv_buf, data1);
	printf("服务器：第二次握手成功!\r\n");
	printf("seq2 : %d\r\n", seq2);
	printf("ack2 : %d\r\n", ack2);
	printf("check2 : %d\r\n", check2);
	printf("my_data2 : %s\r\n", buf);
/*================================================================
*   Describe：
*		第三服务器接受握手	ACK = 1; seq = x + 1; ack = y + 1
================================================================*/

	recv_from_client(recv_buf);
	server_error_req(recv_buf);
	seq3 = get_seq(recv_buf);
	ack3 = get_ack(recv_buf);
	check3 = get_check(recv_buf);
	bzero(buf, sizeof(buf));
	get_data(recv_buf, buf);
	
	if(seq3 == seq1 + 1 && ack3 == seq2 + 1 && (check3 & ACK) > 0 && strcmp(buf, "VMS3") == 0){
		printf("服务器：第三次握手成功!\r\n");
	}
	else{
		printf("服务器：第三次握手失败!\r\n");

		printf("seq3 : %d\r\n", seq3);
		printf("ack3 : %d\r\n", ack3);
		printf("check3 : %d\r\n", check3);
		printf("my_data3 : %s\r\n", buf);
		return -1;
	}

	printf("seq3 : %d\r\n", seq3);
	printf("ack3 : %d\r\n", ack3);
	printf("check3 : %d\r\n", check3);
	printf("my_data3 : %s\r\n", buf);
	
	return 1;
}

/*================================================================
*   Describe : 四次挥手
------------------------------------------------------------------
*	parameter	:
*	@server_id	:	服务器监听描述符	
================================================================*/
int Four_Waves(int server_id){
	char recv_buf[BUF_SIZE] = {0};	
	char send_buf[BUF_SIZE] = {0};
	Datapack data1;
	int parity = 0;
	int seq1 = 0, ack1 = 0, check1 = 0;
	int seq2 = 0, ack2 = 0, check2 = 0;
	int seq3 = 0, ack3 = 0, check3 = 0;
	int seq4 = 0, ack4 = 0, check4 = 0;
	int s_len = sizeof(sock_server);
	int c_len = sizeof(sock_client);
	char buf[100] = "";		//Verify message
	
/*================================================================
*   Describe：
*		第一次服务器接受挥手	FIN = 1; seq = u;
================================================================*/
	printf("服务器：开始四次挥手!\r\n");
	recv_from_client(recv_buf);
	server_error_req(recv_buf);
	printf("服务器：接收到数据!\r\n");
	seq1 = get_seq(recv_buf);
	ack1 = get_ack(recv_buf);
	check1 = get_check(recv_buf);
	bzero(buf, sizeof(buf));
	get_data(recv_buf, buf);
	
	if(seq1 != 0 && (check1 & FIN) > 0 && strcmp(buf, "VMS1") == 0){
		printf("服务器：第一次挥手成功!\r\n");
	}
	else{
		printf("服务器：第一次挥手失败!\r\n");
		printf("seq1 : %d\r\n", seq1);
		printf("ack1 : %d\r\n", ack1);
		printf("check1 : %d\r\n", check1);
		printf("my_data1 : %s\r\n", buf);
		return -1;
	}
	printf("seq1 : %d\r\n", seq1);
	printf("ack1 : %d\r\n", ack1);
	printf("check1 : %d\r\n", check1);
	printf("my_data1 : %s\r\n", buf);
/*================================================================
*   Describe：
*		第二次服务器发起挥手	ACK = 1; seq = v; ack = u + 1
================================================================*/
	seq2 = rand() % 100 + 1;
	ack2 = seq1 + 1;
	check2 = ACK;
	bzero(buf, sizeof(buf));
	strcpy(buf, "VMS2");
	data_init(data1, seq2, ack2, check2, buf);
	BP(data1);
	
	send_to_client(data1);
	server_error_resend(recv_buf, data1);
	printf("服务器：第二次挥手成功!\r\n");
	printf("seq2 : %d\r\n", seq2);
	printf("ack2 : %d\r\n", ack2);
	printf("check2 : %d\r\n", check2);
	printf("my_data2 : %s\r\n", buf);
/*================================================================
*   Describe：
*		第三次服务器发起挥手	FIN = 1; ACK = 1; seq = w; ack = u + 1
================================================================*/
	seq3 = rand() % 100 + 1;
	ack3 = seq1 + 1;
	check3 = FIN | ACK;
	bzero(buf, sizeof(buf));
	strcpy(buf, "VMS3");
	data_init(data1, seq3, ack3, check3, buf);
	BP(data1);
	
	send_to_client(data1);
	server_error_resend(recv_buf, data1);
	printf("服务器：第二次握手成功!\r\n");
	printf("seq3 : %d\r\n", seq3);
	printf("ack3 : %d\r\n", ack3);
	printf("check3 : %d\r\n", check3);
	printf("my_data3 : %s\r\n", buf);

/*================================================================
*   Describe：
*		第四次服务器接受挥手	ACK = 1; seq = u + 1; ack = w + 1
================================================================*/
	recv_from_client(recv_buf);
	server_error_req(recv_buf);
	
	seq4 = get_seq(recv_buf);
	ack4 = get_ack(recv_buf);
	check4 = get_check(recv_buf);
	bzero(buf, sizeof(buf));
	get_data(recv_buf, buf);
	
	if(seq4 == seq1 + 1 && ack4 == seq3 + 1 && (check4 & ACK) > 0 && strcmp(buf, "VMS4") == 0){
		printf("服务器：第四次挥手成功!\r\n");
	}
	else{
		printf("服务器：第四次挥手失败!\r\n");
		printf("seq4 : %d\r\n", seq4);
		printf("ack4 : %d\r\n", ack4);
		printf("check4 : %d\r\n", check4);
		printf("my_data4 : %s\r\n", buf);
		return -1;
	}
	printf("seq4 : %d\r\n", seq4);
	printf("ack4 : %d\r\n", ack4);
	printf("check4 : %d\r\n", check4);
	printf("my_data4 : %s\r\n", buf);
}

